import sys
import os
import logging
import argparse
from datetime import timedelta
import json
import vlc
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QMessageBox, QLabel, QSizePolicy
from PyQt5.QtCore import Qt, QTimer
from moviepy.editor import VideoFileClip, TextClip, CompositeVideoClip, VideoClip
from moviepy.config import change_settings
import pysrt
import time
import re
from mutagen.mp3 import MP3
from mutagen.id3 import ID3, USLT, TIT2, TPE1, TALB

# Configure logging to output to both file and console
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('video_player.log'),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

# 配置 ImageMagick 路径
if sys.platform == "win32":
    # 尝试常见的 ImageMagick 安装路径
    possible_paths = [
        r"C:\Program Files\ImageMagick-7.1.1-Q16-HDRI",
        r"C:\Program Files\ImageMagick-7.1.1-Q16",
        r"C:\Program Files\ImageMagick-7.1.0-Q16-HDRI",
        r"C:\Program Files\ImageMagick-7.1.0-Q16",
        r"C:\Program Files\ImageMagick-7.0.11-Q16-HDRI",
        r"C:\Program Files\ImageMagick-7.0.11-Q16",
    ]
    
    imagemagick_path = None
    for path in possible_paths:
        if os.path.exists(path):
            imagemagick_path = path
            break
    
    if imagemagick_path:
        change_settings({"IMAGEMAGICK_BINARY": os.path.join(imagemagick_path, "magick.exe")})
        logger.info(f"Found ImageMagick at: {imagemagick_path}")
    else:
        logger.warning("ImageMagick not found in common installation paths. Please install ImageMagick or specify the correct path.")

class VideoPlayerWindow(QMainWindow):
    def __init__(self, video_path, subtitle_path):
        super().__init__()
        self.setWindowTitle("Video Player")
        self.video_path = video_path
        self.subtitle_path = subtitle_path
        self.subtitles = pysrt.open(subtitle_path) if subtitle_path and os.path.exists(subtitle_path) else None
        self.mark_points = []  # List of (time_in_seconds, type) where type is 'i' or 'o'
        self.current_mark_index = -1
        self.config_file = os.path.splitext(video_path)[0] + '.config'
        self.cuts = self.load_cuts()
        self.video_clip = None
        self.last_input_time = None
        self.last_output_time = None
        self.subtitle_visible = False  # 添加字幕显示状态标志
        self.current_subtitle = ""  # 当前显示的字幕文本
        self.waiting_for_number = False  # 添加等待数字输入的标志
        self.waiting_for_delete = False  # 添加等待删除数字输入的标志
        self.number_buffer = ""  # 添加数字输入缓冲区
        
        # 计时器相关变量
        self.timer_start_time = None
        self.display_timer = QTimer(self)
        self.display_timer.timeout.connect(self.update_timer_display)
        
        try:
            self.video_clip = VideoFileClip(video_path)
            self.duration = self.video_clip.duration  # In seconds
            self.fps = self.video_clip.fps
        except Exception as e:
            logger.error(f"Failed to load video with moviepy: {str(e)}")
            QMessageBox.critical(self, "Error", f"Cannot load video: {str(e)}")
            sys.exit(1)
            
        # 先初始化UI
        self.init_ui()
        # 然后初始化VLC
        self.init_vlc()
        
        logger.info(f"Initialized video player with video: {video_path}, subtitles: {subtitle_path}, duration: {self.duration}s, fps: {self.fps}")

    def init_vlc(self):
        """Initialize VLC player."""
        # 创建VLC实例时禁用字幕
        self.instance = vlc.Instance('--no-sub-autodetect-file')
        self.player = self.instance.media_player_new()
        self.media = self.instance.media_new(self.video_path)
        self.player.set_media(self.media)
        
        # 根据操作系统设置视频输出
        if sys.platform == "win32":
            self.player.set_hwnd(int(self.video_widget.winId()))
        elif sys.platform == "darwin":
            self.player.set_nsobject(int(self.video_widget.winId()))
        else:
            self.player.set_xwindow(int(self.video_widget.winId()))
            
        if self.subtitles:
            logger.info(f"Loaded subtitles file: {self.subtitle_path}")
            logger.info(f"Number of subtitle entries: {len(self.subtitles)}")
            # 默认显示字幕
            self.subtitle_visible = True
            self.current_subtitle = ""
            self.subtitle_label.setText("")
            
            # 确保VLC播放器不显示字幕
            self.player.video_set_spu(-1)  # 禁用字幕轨道

        # 启动播放和定时器
        self.video_timer = QTimer(self)
        self.video_timer.setInterval(100)  # 每100ms更新一次
        self.video_timer.timeout.connect(self.update_position)
        self.player.play()
        self.video_timer.start()

    def init_ui(self):
        """Initialize the UI with video widget and layout."""
        self.central_widget = QWidget(self)
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
        self.layout.setSpacing(0)  # 设置布局中所有组件之间的间距为0
        self.layout.setContentsMargins(0, 0, 0, 0)  # 设置布局的外边距为0

        # 创建视频widget
        self.video_widget = QWidget()
        self.layout.addWidget(self.video_widget)

        # 添加字幕显示标签
        self.subtitle_label = QLabel("")
        self.subtitle_label.setAlignment(Qt.AlignCenter)
        self.subtitle_label.setStyleSheet("""
            QLabel {
                font-size: 24px;
                font-weight: bold;
                color: #00FF00;
                background-color: black;
                padding: 10px;
                min-height: 60px;  /* 设置最小高度为两行 */
                max-height: 60px;  /* 设置最大高度为两行 */
                margin: 0px;  /* 确保标签本身没有外边距 */
            }
        """)
        self.subtitle_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        self.subtitle_label.setWordWrap(True)  # 允许文字换行
        self.layout.addWidget(self.subtitle_label)

        # 添加视频进度标签
        self.progress_label = QLabel("00:00:00 / 00:00:00")
        self.progress_label.setAlignment(Qt.AlignCenter)
        self.progress_label.setStyleSheet("""
            QLabel {
                font-size: 18px;
                color: #FFFFFF;
                background-color: #333333;
                padding: 5px;
                margin: 0px;
            }
        """)
        self.progress_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        self.layout.addWidget(self.progress_label)

        # 添加计时器显示标签
        self.timer_label = QLabel("00:00:00:000")
        self.timer_label.setAlignment(Qt.AlignCenter)
        self.timer_label.setStyleSheet("QLabel { font-size: 18px; padding: 2px; }")
        self.timer_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        self.layout.addWidget(self.timer_label)

        # 设置窗口大小
        self.setGeometry(100, 100, 800, 600)
		
    def load_cuts(self):
        """Load existing cut points from config file."""
        if os.path.exists(self.config_file):
            with open(self.config_file, 'r') as f:
                return json.load(f)
        return []

    def save_cuts(self):
        """Save cut points to config file."""
        with open(self.config_file, 'w') as f:
            json.dump(self.cuts, f, indent=4)
        logger.info("Saved cut points to config file")

    def time_to_seconds(self, time_str):
        """Convert SRT time string or timedelta to seconds."""
        if isinstance(time_str, timedelta):
            return time_str.total_seconds()
        parts = time_str.replace(',', '.').split(':')
        hours, minutes, seconds = map(float, parts)
        return hours * 3600 + minutes * 60 + seconds

    def seconds_to_timestamp(self, seconds):
        """Convert seconds to timestamp string."""
        return str(timedelta(seconds=int(seconds))).replace(',', '.')

    def adjust_time_with_subtitles(self, mark_time, mark_type):
        """Adjust mark time based on subtitle time blocks."""
        if not self.subtitles:
            return mark_time
        mark_time_ms = mark_time * 1000
        for sub in self.subtitles:
            start_ms = self.time_to_seconds(str(sub.start)) * 1000
            end_ms = self.time_to_seconds(str(sub.end)) * 1000
            if start_ms <= mark_time_ms <= end_ms:
                if mark_type == 'i':
                    adjusted_time = (start_ms - 500) / 1000  # 500ms before start
                    logger.info(f"Adjusted input mark from {mark_time}s to {adjusted_time}s")
                    return max(0, adjusted_time)
                elif mark_type == 'o':
                    adjusted_time = (end_ms + 500) / 1000  # 500ms after end
                    logger.info(f"Adjusted output mark from {mark_time}s to {adjusted_time}s")
                    return adjusted_time
        return mark_time

    def cut_video(self):
        """Cut video based on all cut points in config file."""
        if not self.cuts:
            logger.warning("No cut points found in config file")
            QMessageBox.warning(self, "Warning", "No cut points found in config file")
            return

        logger.info(f"Starting video cutting with {len(self.cuts)} cut points")
        print(f"Starting video cutting with {len(self.cuts)} cut points")

        for cut in self.cuts:
            in_point = cut["in"]
            out_point = cut["out"]
            num = cut["num"]
            
            logger.info(f"Processing cut {num}: in={in_point}, out={out_point}")
            print(f"Processing cut {num}: in={in_point}, out={out_point}")
            
            if in_point >= out_point:
                logger.error(f"Invalid cut points for cut {num}: input mark must be before output mark")
                continue
                
            output_path = f"cut_{num:03d}_{os.path.splitext(os.path.basename(self.video_path))[0]}.mp4"
            try:
                clip = VideoFileClip(self.video_path).subclip(in_point, out_point)
                clip.write_videofile(output_path, codec="libx264", audio_codec="aac")
                clip.close()
                logger.info(f"Successfully cut video {num} from {in_point}s to {out_point}s, saved as {output_path}")
                print(f"Successfully cut video {num} from {in_point}s to {out_point}s, saved as {output_path}")
            except Exception as e:
                logger.error(f"Failed to cut video {num}: {str(e)}")
                QMessageBox.critical(self, "Error", f"Failed to cut video {num}: {str(e)}")
                print(f"Failed to cut video {num}: {str(e)}")

        logger.info("Video cutting completed")
        print("Video cutting completed")

    def write_current_marks(self):
        """Write current input and output marks to config file."""
        if self.last_input_time is None or self.last_output_time is None:
            logger.warning("Need both input and output marks to write")
            QMessageBox.warning(self, "Warning", "Need both input and output marks to write")
            return

        new_cut = {
            "num": len(self.cuts) + 1,
            "in": self.last_input_time,
            "out": self.last_output_time
        }
        self.cuts.append(new_cut)
        
        # 按照输入时间戳排序
        self.cuts.sort(key=lambda x: x["in"])
        
        # 重新编号
        for i, cut in enumerate(self.cuts, start=1):
            cut["num"] = i
            
        self.save_cuts()
        logger.info(f"Added new cut point and reordered: {new_cut}")
        print(f"已添加新的剪辑点并重新排序")
        
        # 显示当前所有剪辑点
        print("\n当前所有剪辑点:")
        for cut in self.cuts:
            print(f"编号: {cut['num']}, 开始时间: {self.seconds_to_timestamp(cut['in'])}, 结束时间: {self.seconds_to_timestamp(cut['out'])}")

    def delete_cut(self, num):
        """Delete the nth cut point and renumber subsequent cuts."""
        if 1 <= num <= len(self.cuts):
            # 删除指定编号的剪辑点
            self.cuts.pop(num - 1)
            
            # 重新编号后续的剪辑点
            for i, cut in enumerate(self.cuts[num-1:], start=num):
                cut["num"] = i
                
            self.save_cuts()
            logger.info(f"Deleted cut point {num} and renumbered subsequent cuts")
            print(f"已删除剪辑点 {num} 并重新编号后续剪辑点")
        else:
            logger.warning(f"Invalid cut number: {num}")
            QMessageBox.warning(self, "Warning", f"无效的剪辑点编号: {num}")

    def update_position(self):
        """Update current position periodically."""
        if self.player.get_state() in [vlc.State.Ended, vlc.State.Stopped]:
            self.player.stop()
            self.player.play()
            logger.info("Reached end of video, restarting")
        
        # 更新视频进度显示
        current_time = self.player.get_time() / 1000  # 转换为秒
        total_time = self.duration
        current_str = self.seconds_to_timestamp(current_time)
        total_str = self.seconds_to_timestamp(total_time)
        # 格式化当前时间，包含秒数
        current_time_str = f"{current_str} ({current_time:.3f} S)"
        self.progress_label.setText(f"{current_time_str} / {total_str}")
        
        # 更新字幕显示
        if self.subtitles and self.subtitle_visible:
            current_sub = None
            
            # 查找当前时间对应的字幕
            for sub in self.subtitles:
                start_time = self.time_to_seconds(str(sub.start))
                end_time = self.time_to_seconds(str(sub.end))
                if start_time <= current_time <= end_time:
                    current_sub = sub
                    break
            
            # 更新字幕显示
            if current_sub and current_sub.text != self.current_subtitle:
                self.current_subtitle = current_sub.text
                self.subtitle_label.setText(self.current_subtitle)
                logger.debug(f"Displaying subtitle: {self.current_subtitle}")
            elif not current_sub and self.current_subtitle:
                self.current_subtitle = ""
                self.subtitle_label.setText("")
                logger.debug("Clearing subtitle display")

    def keyPressEvent(self, event):
        """Handle keyboard shortcuts."""
        key = event.key()
        modifiers = event.modifiers()

        if key == Qt.Key_Space:
            if self.player.is_playing():
                self.player.pause()
            else:
                self.player.play()
            logger.info(f"Video {'paused' if not self.player.is_playing() else 'playing'}")
        
        elif key == Qt.Key_S:
            self.player.stop()
            logger.info("Stopped video and reset to start")
        
        elif key == Qt.Key_I:
            current_time = self.player.get_time() / 1000  # Convert ms to seconds
            self.last_input_time = current_time
            self.stop_timer()  # 停止当前计时器
            self.start_timer()  # 开始新的计时器
            logger.info(f"Set input mark point at {current_time}s")
            print(f"Input mark set at {self.seconds_to_timestamp(current_time)}")
        
        elif key == Qt.Key_O:
            current_time = self.player.get_time() / 1000
            self.last_output_time = current_time
            logger.info(f"Set output mark point at {current_time}s")
            print(f"Output mark set at {self.seconds_to_timestamp(current_time)}")
        
        elif key == Qt.Key_W:
            if self.last_input_time is not None and self.last_output_time is not None:
                new_cut = {
                    "num": len(self.cuts) + 1,
                    "in": self.last_input_time,
                    "out": self.last_output_time
                }
                self.cuts.append(new_cut)
                
                # 按照输入时间戳排序
                self.cuts.sort(key=lambda x: x["in"])
                
                # 重新编号
                for i, cut in enumerate(self.cuts, start=1):
                    cut["num"] = i
                    
                self.save_cuts()
                logger.info(f"Added new cut point and reordered: {new_cut}")
                print(f"已添加新的剪辑点并重新排序")
                
                # 显示当前所有剪辑点
                print("\n当前所有剪辑点:")
                for cut in self.cuts:
                    print(f"编号: {cut['num']}, 开始时间: {self.seconds_to_timestamp(cut['in'])}, 结束时间: {self.seconds_to_timestamp(cut['out'])}")
                
                # 使用当前的输出点作为新的输入点
                self.last_input_time = self.last_output_time
                logger.info(f"Set new input mark point using last output point: {self.last_input_time}s")
                print(f"新的输入点已设置为上一次的输出点: {self.seconds_to_timestamp(self.last_input_time)}")
            else:
                logger.warning("Need both input and output marks to write")
                QMessageBox.warning(self, "Warning", "Need both input and output marks to write")
        
        elif key == Qt.Key_D:
            # 等待下一个按键
            self.waiting_for_delete = True
            self.number_buffer = ""  # 清空数字缓冲区
            logger.info("Waiting for number input after D key")
            print("请输入要删除的剪辑点编号")
        
        elif self.waiting_for_delete:
            if key == Qt.Key_Return or key == Qt.Key_Enter:
                # 处理完整的数字输入
                if self.number_buffer:
                    try:
                        num = int(self.number_buffer)
                        self.delete_cut(num)
                    except ValueError:
                        logger.warning("Invalid number input")
                        QMessageBox.warning(self, "Warning", "请输入有效的数字")
                self.waiting_for_delete = False
                self.number_buffer = ""
            elif key == Qt.Key_Escape:
                # 取消删除操作
                self.waiting_for_delete = False
                self.number_buffer = ""
                logger.info("Cancelled delete operation")
            elif event.text().isdigit():
                # 将数字添加到缓冲区
                self.number_buffer += event.text()
                print(f"当前输入: {self.number_buffer}")
            else:
                # 非数字输入，取消删除操作
                self.waiting_for_delete = False
                self.number_buffer = ""
                logger.info("Invalid input, cancelled delete operation")

        elif key == Qt.Key_Up:
            # 获取当前时间
            current_time = self.player.get_time() / 1000
            # 从cuts中找到所有小于当前时间的输入点
            input_points = [(cut["in"], i) for i, cut in enumerate(self.cuts) if cut["in"] < current_time]
            if input_points:
                # 按时间降序排序
                input_points.sort(reverse=True)
                # 如果当前时间等于最近的输入点，则跳到下一个
                if input_points[0][0] == current_time and len(input_points) > 1:
                    target_time = input_points[1][0]
                else:
                    target_time = input_points[0][0]
                self.player.set_time(int(target_time * 1000))
                logger.info(f"Jumped to previous input mark at {target_time}s")
        
        elif key == Qt.Key_Down:
            # 获取当前时间
            current_time = self.player.get_time() / 1000
            # 从cuts中找到所有大于当前时间的输入点
            input_points = [(cut["in"], i) for i, cut in enumerate(self.cuts) if cut["in"] > current_time]
            if input_points:
                # 按时间升序排序
                input_points.sort()
                # 如果当前时间等于最近的输入点，则跳到下一个
                if input_points[0][0] == current_time and len(input_points) > 1:
                    target_time = input_points[1][0]
                else:
                    target_time = input_points[0][0]
                self.player.set_time(int(target_time * 1000))
                logger.info(f"Jumped to next input mark at {target_time}s")
        
        elif key == Qt.Key_G:
            # 检查是否有最近设置的输入点
            if self.last_input_time is not None:
                # 跳转到该时间点
                self.player.set_time(int(self.last_input_time * 1000))
                # 重置计时器
                self.stop_timer()
                self.start_timer()
                # 开始播放
                self.player.play()
                logger.info(f"Jumped to last input mark at {self.last_input_time}s and started timer")
                print(f"已跳转到最近的输入点 {self.seconds_to_timestamp(self.last_input_time)} 并开始计时")
            else:
                logger.warning("No input mark has been set yet")
                print("还没有设置过输入点，请先按 I 键设置输入点")
        
        elif key == Qt.Key_Left:
            new_time = max(0, (self.player.get_time() / 1000) - 2)
            self.player.set_time(int(new_time * 1000))
            logger.info(f"Jumped back 2s to {new_time}s")
        
        elif key == Qt.Key_Right:
            new_time = min(self.duration, (self.player.get_time() / 1000) + 2)
            self.player.set_time(int(new_time * 1000))
            logger.info(f"Jumped forward 2s to {new_time}s")
        
        elif key == Qt.Key_X:
            self.cut_video()
            logger.info("Initiated video cut")
        
        elif key == Qt.Key_Q:
            logger.info("User requested exit")
            self.close()

        elif key == Qt.Key_T:
            self.toggle_subtitles()

    def closeEvent(self, event):
        """Clean up on window close."""
        self.player.stop()
        self.display_timer.stop()
        if self.video_clip:
            self.video_clip.close()
        logger.info("Video player closed")
        event.accept()

    def update_timer_display(self):
        """更新计时器显示"""
        if self.timer_start_time is not None:
            elapsed = time.time() - self.timer_start_time
            hours = int(elapsed // 3600)
            minutes = int((elapsed % 3600) // 60)
            seconds = int(elapsed % 60)
            milliseconds = int((elapsed % 1) * 1000)  # 获取毫秒部分
            self.timer_label.setText(f"{hours:02d}:{minutes:02d}:{seconds:02d}:{milliseconds:03d}")

    def start_timer(self):
        """开始计时器"""
        self.timer_start_time = time.time()
        self.display_timer.start(10)  # 每10毫秒更新一次，使毫秒显示更流畅

    def stop_timer(self):
        """停止计时器"""
        self.display_timer.stop()
        self.timer_start_time = None
        self.timer_label.setText("00:00:00:000")

    def toggle_subtitles(self):
        """切换字幕显示状态"""
        if not self.subtitles:
            logger.warning("No subtitles available")
            return
            
        self.subtitle_visible = not self.subtitle_visible
        if not self.subtitle_visible:
            self.current_subtitle = ""
            self.subtitle_label.setText("")
        logger.info(f"Subtitles {'enabled' if self.subtitle_visible else 'disabled'}")

def cut_subtitle(subtitle_path, start_time, end_time, output_path):
    """Cut subtitle file according to the given time range."""
    try:
        subs = pysrt.open(subtitle_path)
        new_subs = pysrt.SubRipFile()
        
        # 将时间转换为毫秒
        start_ms = start_time * 1000
        end_ms = end_time * 1000
        
        # 筛选在时间范围内的字幕
        for sub in subs:
            sub_start = sub.start.ordinal
            sub_end = sub.end.ordinal
            
            # 如果字幕在时间范围内，调整时间并添加
            if sub_start >= start_ms and sub_end <= end_ms:
                # 调整时间
                sub.start.ordinal -= start_ms
                sub.end.ordinal -= start_ms
                new_subs.append(sub)
            # 如果字幕跨越开始时间
            elif sub_start < start_ms and sub_end > start_ms:
                sub.start.ordinal = 0
                sub.end.ordinal -= start_ms
                new_subs.append(sub)
            # 如果字幕跨越结束时间
            elif sub_start < end_ms and sub_end > end_ms:
                sub.end.ordinal = end_ms - start_ms
                new_subs.append(sub)
        
        # 保存新的字幕文件
        new_subs.save(output_path, encoding='utf-8')
        return True
    except Exception as e:
        logger.error(f"Failed to cut subtitle: {str(e)}")
        return False

def parse_srt_time(srt_time):
    """Convert SRT timestamp (e.g., 00:00:01,000) to LRC timestamp (e.g., [00:01.00])."""
    hours, minutes, seconds_ms = srt_time.split(':')
    seconds, milliseconds = seconds_ms.split(',')
    total_minutes = int(hours) * 60 + int(minutes)
    lrc_time = f"[{total_minutes:02d}:{int(seconds):02d}.{int(milliseconds[:2]):02d}]"
    return lrc_time

def srt_to_lrc(srt_file, lrc_file):
    """Convert an SRT file to an LRC file."""
    try:
        with open(srt_file, 'r', encoding='utf-8') as f:
            srt_content = f.read()

        subtitle_blocks = srt_content.strip().split('\n\n')
        lrc_lines = []

        for block in subtitle_blocks:
            lines = block.strip().split('\n')
            if len(lines) < 3:
                continue

            timestamp_line = lines[1]
            match = re.match(r'(\d{2}:\d{2}:\d{2},\d{3})\s-->\s(\d{2}:\d{2}:\d{2},\d{3})', timestamp_line)
            if not match:
                continue

            start_time = match.group(1)
            lrc_timestamp = parse_srt_time(start_time)
            subtitle_text = ' '.join(lines[2:]).strip()
            if subtitle_text:
                lrc_lines.append(f"{lrc_timestamp}{subtitle_text}")

        with open(lrc_file, 'w', encoding='utf-8') as f:
            f.write("[ti:Converted from SRT]\n")
            f.write("[ar:Unknown]\n")
            f.write("[al:Unknown]\n")
            f.write("\n")
            f.write('\n'.join(lrc_lines))

        logger.info(f"Successfully converted {srt_file} to {lrc_file}")
        return True

    except Exception as e:
        logger.error(f"Error converting SRT to LRC: {str(e)}")
        return False

def extract_audio_from_video(video_path, output_mp3_path=None):
    """Extract audio from video file and save as MP3."""
    try:
        if output_mp3_path is None:
            output_mp3_path = os.path.splitext(video_path)[0] + '.mp3'

        with VideoFileClip(video_path) as video:
            audio = video.audio
            audio.write_audiofile(output_mp3_path)
            audio.close()

        logger.info(f"Successfully extracted audio to {output_mp3_path}")
        return output_mp3_path

    except Exception as e:
        logger.error(f"Error extracting audio: {str(e)}")
        return None

def embed_lyrics_to_mp3(mp3_path, lrc_path, language='eng'):
    """Embed LRC lyrics into MP3 file."""
    try:
        with open(lrc_path, 'r', encoding='utf-8') as f:
            lrc_content = f.read()

        audio = MP3(mp3_path, ID3=ID3)

        try:
            audio.add_tags()
        except:
            pass

        # 从MP3文件名中提取专辑名称
        album_name = os.path.splitext(os.path.basename(mp3_path))[0]
        # 移除可能的前缀（如 cut_001_）
        album_name = re.sub(r'^cut_\d+_', '', album_name)
        # 移除可能的后缀（如 _lrc）
        album_name = re.sub(r'_lrc$', '', album_name)

        # 添加艺术家信息
        audio.tags.add(TPE1(encoding=3, text='learnEnglishByAV'))
        # 添加专辑信息
        audio.tags.add(TALB(encoding=3, text=album_name))
        # 添加歌词
        audio.tags.add(USLT(encoding=3, lang=language, desc='Lyrics', text=lrc_content))
        audio.save()
        
        logger.info(f"Successfully embedded lyrics, artist and album into {mp3_path}")
        return True

    except Exception as e:
        logger.error(f"Error embedding lyrics: {str(e)}")
        return False

def process_video_with_config(video_path, config_path):
    """Process video with configuration file."""
    try:
        # 读取配置文件
        with open(config_path, 'r') as f:
            config = json.load(f)

        # 获取视频文件名（不含扩展名）
        video_name = os.path.splitext(os.path.basename(video_path))[0]
        
        # 创建主输出文件夹（与视频同名）
        main_output_dir = os.path.join(os.path.dirname(video_path), video_name)
        os.makedirs(main_output_dir, exist_ok=True)
        
        # 创建音频输出文件夹
        audio_output_dir = os.path.join(main_output_dir, "audio")
        os.makedirs(audio_output_dir, exist_ok=True)
        
        # 创建带嵌入歌词的音频输出文件夹
        audio_embed_lrc_dir = os.path.join(main_output_dir, "audio_embed_lrc")
        os.makedirs(audio_embed_lrc_dir, exist_ok=True)
        
        logger.info(f"创建输出文件夹: {main_output_dir}")
        logger.info(f"创建音频文件夹: {audio_output_dir}")
        logger.info(f"创建带嵌入歌词的音频文件夹: {audio_embed_lrc_dir}")
        
        # 处理每个剪切片段
        last_cut_num = 0
        for cut in config:
            in_point = cut["in"]
            out_point = cut["out"]
            num = cut["num"]
            last_cut_num = num  # 记录最后一个处理的编号
            
            # 生成输出文件名
            output_video = os.path.join(main_output_dir, f"cut_{num:03d}_{video_name}.mp4")
            output_mp3 = os.path.join(audio_output_dir, f"cut_{num:03d}_{video_name}.mp3")
            output_mp3_embed = os.path.join(audio_embed_lrc_dir, f"cut_{num:03d}_{video_name}_lrc.mp3")
            output_lrc = os.path.join(audio_output_dir, f"cut_{num:03d}_{video_name}.lrc")
            output_srt = os.path.join(main_output_dir, f"cut_{num:03d}_{video_name}.srt")
            
            # 剪切视频
            clip = VideoFileClip(video_path).subclip(in_point, out_point)
            clip.write_videofile(output_video, codec="libx264", audio_codec="aac")
            clip.close()
            
            # 提取音频（不带歌词）
            extract_audio_from_video(output_video, output_mp3)
            
            # 如果有字幕文件，转换为LRC并处理
            subtitle_path = os.path.splitext(video_path)[0] + '.srt'
            if os.path.exists(subtitle_path):
                # 剪切字幕
                cut_subtitle(subtitle_path, in_point, out_point, output_srt)
                # 转换为LRC
                srt_to_lrc(output_srt, output_lrc)
                
                # 复制MP3文件到带嵌入歌词的目录
                import shutil
                shutil.copy2(output_mp3, output_mp3_embed)
                # 嵌入歌词到复制的MP3文件
                embed_lyrics_to_mp3(output_mp3_embed, output_lrc)
            
            logger.info(f"Successfully processed cut {num}")
            print(f"已处理片段 {num}:")
            print(f"  - 视频文件: {output_video}")
            print(f"  - 音频文件: {output_mp3}")
            if os.path.exists(subtitle_path):
                print(f"  - 字幕文件: {output_srt}")
                print(f"  - 歌词文件: {output_lrc}")
                print(f"  - 带嵌入歌词的音频文件: {output_mp3_embed}")
        
        # 保存最后一个处理的编号到 .cut_pos 文件
        save_cut_position(video_path, last_cut_num)
            
        return True

    except Exception as e:
        logger.error(f"Error processing video: {str(e)}")
        return False

def process_folder_with_watermark(folder_path):
    """Process all MP4 files in a folder and add watermark, overwriting original files."""
    try:
        # 获取文件夹中所有的MP4文件
        mp4_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.mp4')]
        
        if not mp4_files:
            logger.warning(f"No MP4 files found in folder: {folder_path}")
            return False
        
        for mp4_file in mp4_files:
            input_path = os.path.join(folder_path, mp4_file)
            temp_path = os.path.join(folder_path, f"temp_{mp4_file}")
            
            try:
                # 处理单个视频
                video = VideoFileClip(input_path)
                
                # 使用ffmpeg直接处理，保持原视频质量
                ffmpeg_params = [
                    '-vf', f'drawtext=text=learnEnglishByAV:fontsize=14:fontcolor=white:x=w-text_w-10:y=10',
                    '-g', '30',
                    '-keyint_min', '30',
                    '-sc_threshold', '0',
                    '-preset', 'medium',
                    '-crf', '18',
                    '-threads', '4',
                    '-c:v', 'libx264',
                    '-profile:v', 'high',
                    '-level', '4.1',
                    '-pix_fmt', 'yuv420p'
                ]
                
                # 先输出到临时文件
                video.write_videofile(temp_path,
                                    codec="libx264",
                                    audio_codec="aac",
                                    ffmpeg_params=ffmpeg_params)
                
                video.close()
                
                # 删除原文件并重命名临时文件
                os.remove(input_path)
                os.rename(temp_path, input_path)
                
                logger.info(f"Successfully processed: {mp4_file}")
            except Exception as e:
                logger.error(f"Failed to process {mp4_file}: {str(e)}")
                # 如果处理失败，删除临时文件（如果存在）
                if os.path.exists(temp_path):
                    os.remove(temp_path)
                continue
        
        logger.info(f"All videos in folder have been processed: {folder_path}")
        return True
    except Exception as e:
        logger.error(f"Failed to process folder: {str(e)}")
        return False

def process_folder_to_audio(folder_path):
    """Process all MP4 files in a folder to MP3 with embedded LRC subtitles."""
    try:
        # 获取文件夹中所有的MP4文件
        mp4_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.mp4')]
        
        if not mp4_files:
            logger.warning(f"No MP4 files found in folder: {folder_path}")
            return False
        
        # 创建输出文件夹
        folder_name = os.path.basename(folder_path)
        parent_dir = os.path.dirname(folder_path)
        output_dir = os.path.join(parent_dir, f"{folder_name}_audio")
        os.makedirs(output_dir, exist_ok=True)
        
        for mp4_file in mp4_files:
            try:
                # 构建文件路径
                video_path = os.path.join(folder_path, mp4_file)
                base_name = os.path.splitext(mp4_file)[0]
                srt_path = os.path.join(folder_path, f"{base_name}.srt")
                
                # 检查字幕文件是否存在
                if not os.path.exists(srt_path):
                    logger.error(f"Subtitle file not found for {mp4_file}")
                    continue
                
                # 转换字幕
                lrc_content = srt_to_lrc(srt_path, f"{base_name}.lrc")
                if not lrc_content:
                    logger.error(f"Failed to convert subtitle for {mp4_file}")
                    continue
                
                # 提取音频
                video = VideoFileClip(video_path)
                output_mp3 = os.path.join(output_dir, f"{base_name}.mp3")
                
                # 使用ffmpeg提取音频并嵌入歌词
                ffmpeg_params = [
                    '-i', video_path,
                    '-vn',  # 不处理视频
                    '-acodec', 'libmp3lame',  # 使用MP3编码器
                    '-q:a', '2',  # 设置音频质量（0-9，2是高质量）
                    '-metadata', f'lyrics={lrc_content}',  # 嵌入歌词
                    output_mp3
                ]
                
                # 使用subprocess调用ffmpeg
                import subprocess
                subprocess.run(['ffmpeg', *ffmpeg_params], check=True)
                
                video.close()
                logger.info(f"Successfully processed: {mp4_file}")
                
            except Exception as e:
                logger.error(f"Failed to process {mp4_file}: {str(e)}")
                continue
        
        logger.info(f"All audio files have been saved to folder: {output_dir}")
        return True
    except Exception as e:
        logger.error(f"Failed to process folder: {str(e)}")
        return False

def get_cut_position(video_path):
    """获取视频的剪辑位置记录"""
    cut_pos_file = os.path.splitext(video_path)[0] + '.cut_pos'
    if os.path.exists(cut_pos_file):
        try:
            with open(cut_pos_file, 'r') as f:
                return int(f.read().strip())
        except Exception as e:
            logger.error(f"读取剪辑位置记录失败: {str(e)}")
    return 1  # 如果没有记录文件，从1开始

def save_cut_position(video_path, position):
    """保存视频的剪辑位置记录"""
    cut_pos_file = os.path.splitext(video_path)[0] + '.cut_pos'
    try:
        # 保存时加1，表示下一个要处理的位置
        with open(cut_pos_file, 'w') as f:
            f.write(str(position + 1))
        logger.info(f"已保存剪辑位置记录: {position + 1}")
    except Exception as e:
        logger.error(f"保存剪辑位置记录失败: {str(e)}")

def main():
    parser = argparse.ArgumentParser(
        description='视频处理工具 - 支持视频剪辑、添加水印、音频转换等功能',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''
使用示例:
  1. 播放视频和字幕:
     python cut-video.py -p video.mkv video.srt

  2. 根据配置文件剪辑视频:
     python cut-video.py -x video.mkv video.config [number]
     (会创建 video 文件夹，并在其中保存剪辑片段和对应的字幕)
     [number] 是可选的，表示从第 number 个剪辑点开始处理到文件末尾
     如果不指定 number，则从记录的剪辑点开始处理

  3. 为文件夹中的所有视频添加水印:
     python cut-video.py -a videos_folder
     (直接在原文件夹中处理，覆盖原文件)

  4. 将视频转换为带歌词的MP3:
     python cut-video.py -e videos_folder
     (会在上级目录创建 videos_folder_audio 文件夹，保存转换后的MP3文件)

注意事项:
  - 使用 -x 选项时，需要确保配置文件格式正确
  - 使用 -a 选项时，会直接覆盖原视频文件
  - 使用 -e 选项时，需要确保每个视频都有对应的SRT字幕文件
'''
    )
    
    parser.add_argument('-p', nargs=2, metavar=('VIDEO', 'SUBTITLE'),
                      help='播放视频和字幕\n'
                           'VIDEO: 视频文件路径\n'
                           'SUBTITLE: 字幕文件路径')
    
    parser.add_argument('-x', nargs='+', metavar='ARGS',
                      help='根据配置文件剪辑视频\n'
                           '参数格式: VIDEO CONFIG [NUMBER]\n'
                           'VIDEO: 视频文件路径\n'
                           'CONFIG: 配置文件路径，包含剪辑时间点\n'
                           '[NUMBER]: 可选，从第NUMBER个剪辑点开始处理到文件末尾')
    
    parser.add_argument('-a', nargs=1, metavar='FOLDER',
                      help='为文件夹中的所有MP4文件添加水印\n'
                           'FOLDER: 包含MP4文件的文件夹路径')
    
    parser.add_argument('-e', nargs=1, metavar='FOLDER',
                      help='将文件夹中的视频转换为带歌词的MP3\n'
                           'FOLDER: 包含MP4文件和对应SRT字幕的文件夹路径')
    
    args = parser.parse_args()
    
    if args.p:
        # 播放模式
        app = QApplication(sys.argv)
        window = VideoPlayerWindow(args.p[0], args.p[1])
        window.show()
        sys.exit(app.exec_())
    elif args.x:
        # 配置文件处理模式
        video_path = args.x[0]
        config_path = args.x[1]
        
        # 读取配置文件
        with open(config_path, 'r') as f:
            cuts = json.load(f)
            
        # 获取最后一个剪辑点的编号
        last_cut_num = cuts[-1]["num"] if cuts else 0
        
        # 确定起始剪辑点
        if len(args.x) > 2:
            # 如果用户指定了起始点，使用用户指定的点
            start_cut = int(args.x[2])
            print(f"从用户指定的剪辑点 {start_cut} 开始处理")
        else:
            # 否则从记录文件中读取
            start_cut = get_cut_position(video_path)
            print(f"从记录的剪辑点 {start_cut} 开始处理")
        
        # 检查是否需要处理
        # 将记录的编号减1，与配置文件中的最后一个编号比较
        if start_cut - 1 == last_cut_num:
            print(f"所有视频片段已经处理完成，无需继续处理")
            return
        elif start_cut - 1 > last_cut_num:
            print(f"错误：记录的剪辑点 {start_cut} 超出了配置文件中的剪辑点数量 {last_cut_num}")
            return
        
        # 只处理从起始点到最后的剪辑
        cuts = cuts[start_cut-1:]
        # 重新编号
        for i, cut in enumerate(cuts, start=start_cut):
            cut["num"] = i
            
        # 创建临时配置文件
        temp_config = os.path.join(os.path.dirname(config_path), 'temp_config.json')
        with open(temp_config, 'w') as f:
            json.dump(cuts, f, indent=4)
            
        # 处理视频
        if process_video_with_config(video_path, temp_config):
            print("视频处理完成")
            # 保存最后一个处理的编号
            save_cut_position(video_path, last_cut_num)
        else:
            print("视频处理失败")
            
        # 删除临时配置文件
        if os.path.exists(temp_config):
            os.remove(temp_config)
            
    elif args.a:
        # 添加水印模式（处理整个文件夹）
        if process_folder_with_watermark(args.a[0]):
            print("水印添加完成")
        else:
            print("水印添加失败")
    elif args.e:
        # 音频转换模式
        if process_folder_to_audio(args.e[0]):
            print("音频转换完成")
        else:
            print("音频转换失败")
    else:
        parser.print_help()

if __name__ == "__main__":
    main()